﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using MovieRental.DataInterfaces;
using MovieRental.Entities;
using MovieRental.BuisnessComponents.Exceptions;
using MovieRental.BuisnessComponents.Helpers;
using MovieRental.BuisnessComponents.Base;

namespace MovieRental.BuisnessComponents
{
    public class CustomerComponent : BaseSetComponent<CustomerInfo, Guid, ICustomerRepository>
    {
        public CustomerComponent(ICustomerRepository repository)
            : base(repository)
        {
        }

        private const string emailRegex = @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$";
        private const string phoneRegex = @"(^(\+?\-? *[0-9]+)([,0-9 ]*)([0-9 ])*$)|(^ *$)";

        protected override bool Equals(CustomerInfo obj1, CustomerInfo obj2)
        {
            return (obj1.FirstName == obj2.FirstName &&
                obj1.LastName == obj2.LastName &&
                obj1.Email == obj2.Email);
        }

        public bool VerifyName(string name)
        {
            return !string.IsNullOrWhiteSpace(name);
        }

        public bool VerifyEmail(string email)
        {
            if (string.IsNullOrEmpty(email))
                return false;
            Regex r = new Regex(emailRegex);
            return r.IsMatch(email); 
        }

        public bool VerifyPhoneNo(string phoneNo)
        {
            if (string.IsNullOrEmpty(phoneNo))
                return false;
            Regex r = new Regex(phoneRegex);
            return r.IsMatch(phoneNo);
        }

        public override void Verify(CustomerInfo customer)
        {  
            if (!VerifyEmail(customer.Email))
                throw new RegexException(customer, "Email");
            if (!VerifyName(customer.FirstName))
                throw new EmptyFieldException(customer, "FirstName");
            if (!VerifyName(customer.LastName))
                throw new EmptyFieldException(customer, "LastName");
            if (!VerifyPhoneNo(customer.PhoneNo))
                throw new RegexException(customer, "PhoneNo");
            base.Verify(customer);
        }

        public bool CustomerExists(Guid id)
        {
            return Repository.ContainsCustomer(id);
        }

        public IEnumerable<CustomerInfo> SearchCustomersByName(string searchString)
        {
            string[] words = searchString.Split(' ');
            Func<CustomerInfo, string> concatNames = c => c.FirstName + " " + c.LastName;
            var request = from customer in Repository.LoadAll()
                          where concatNames(customer).GetSimilarWordsCoefficient(searchString) > 0
                          orderby concatNames(customer).GetSimilarWordsCoefficient(searchString) descending
                          select customer;
            return request;
        }

        public IEnumerable<CustomerInfo> GetTopSpendthrifts()
        {
            var loanCartComponent = ComponentFactory.Instance.GetLoanCartComponent();
            var request = from customer in Repository.LoadAll()
                          orderby loanCartComponent.CountSpentMoney(customer.Id) descending
                          select customer;
            return request.Take(10);
        }

        public bool CanDelete(CustomerInfo customer)
        {
            return ComponentFactory.Instance.GetLoanCartComponent().GetNotReturnedEditionsCount(customer.Id) == 0;
        }
        
    }
}
